//这个必须得创建,且必须是这个名,主要作用是指定任务
//注意dist文件夹中的文件不可以动,无论是什么原因都不能动,要想动dist文件夹中的文件时,有一个方法时把整个文件夹都删了,然后再重新自动生成就好了


//导入gulp使用
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');//html任务
const cleanCss = require('gulp-clean-css');//css任务
const autoprefixer = require('gulp-autoprefixer');//css兼容性前缀
const uglify = require('gulp-uglify');//js任务
const babel = require('gulp-babel');//ES6转ES5
const del = require('del');//删除:由于dist目录是每次执行任务时自动生成的,所以为了避免上一次旧的代码对新的代码造成影响,我们一般会在开启任务之前先把dist目录删掉
const connect = require('gulp-connect');//开启服务器
const proxy = require('http-proxy-middleware');//前后端的端口号不一致时的一个基于Node.js的一个中间层介质
const sass = require('gulp-sass');//将.scss编程为.css格式的

/*
    程序优化(1)可以将所有文件的文件路径统一保管到一起,同一管理,方便操作
*/
const paths = {
    html: {
        src: 'src/**/*.html',
        dest: 'dist'
    },
    css: {
        //src: 'src/css/**/*.css',//更改了格式名为.scss
        src: 'src/css/**/*.scss',
        dest: 'dist/css'
    },
    js: {
        src: 'src/js/**/*.js',
        dest: 'dist/js'
    },
    img: {
        src: 'src/images/**/*',
        dest: 'dist/images'
    },
    libs: {
        src: 'src/libs/**/*',
        dest: 'dist/libs'
    }
}


//指定任务,指定任务有一个 .task()方法,在高版本中不再使用.task()的低级用法了,有更高级的用法,用一个函数全解决
// gulp.task()

//0.指定一个删除dist目录的任务:这个任务需要在最开始的时候运行,要不然刚生成就给删除了
const delDist = () => {
    return del(['dist'])//删除哪个文件夹,这里的参数就写哪个就行
}


//1.指定html任务;压缩html,步骤八src中的html文件取出来,压缩,然后放在dist文件夹中

    //gulp方法src是取出文件,src/**/*.html:意为**所有目录,*所有文件,意为src文件夹下的所有目录下的所有html文件
    //.pipe()方法:管的意思,即流水线的意思,车间,所有的压缩、放入都是在这个地方里都完成的
    //gulp方法gulp-htmlmin,这也是个依赖,项目的时候使用,上线之后就不用了,所以也得局部安装一下,这个是压缩文件的意思(需要传参才能正常工作,因为参数太多,所以的用对象的方法),在车间中完成,所以的在pipe()中
    //glup方法gulp.dest();意为放入到哪个文件夹中

const html = () =>{
    // return gulp.src('src/**/*.html')
    return gulp.src(paths.html.src)//统一管理后,可使用对象点的方法直接访问,以下的直接改了,不留原代码了
    .pipe(htmlmin({
        collapseWhitespace : true,//单纯的压缩html
        removeComments : true,//清除HTML注释
        collapseBooleanAttributes : true,//省略布尔属性的值 <input checked="true"/> ==> <input checked />
        removeEmptyAttributes : true,//删除所有空格作属性值 <input id="" /> ==> <input />
        removeScriptTypeAttributes: false,//删除<script>的type="text/javascript"
        removeStyleLinkTypeAttributes : true,//删除<style>和<link>的type="text/css"
        minifyJS : true,//压缩页面JS
        minifyCSS : true//压缩页面CSS
    }))
    // .pipe(gulp.dest('dist'));
    .pipe(gulp.dest(paths.html.dest))
    .pipe(connect.reload());//注意要想实现热更新,还得配合html css 和 js 改变后重新加载的语句:pipe(connect.reload())
}


//2.指定css任务,先把所有css文件取出来,加上兼容前缀,再压缩,最后放到dist目录里
const css = () =>{
    return gulp.src(paths.css.src)
    .pipe(sass())//scss代码编辑为css格式的
    .pipe(autoprefixer( {
        overrideBrowserslist:['last 2 versions']
    }))//基于gulp的依赖方法autoprefixer():给加css兼容性前缀,注意要先加前缀再压缩才符合流程,需要参数
    .pipe(cleanCss())//cleanCss():压缩
    .pipe(gulp.dest(paths.css.dest))
    .pipe(connect.reload());
}


//3.指定js任务,把js文件取出来,先ES6转ES5,再压缩,最后放到dist里
const js = () =>{
    return gulp.src(paths.js.src)
    .pipe(babel({
      presets: ['@babel/env']
    }))//基于gulp的依赖方法babel()方法,将js中的es6格式语法转为以es5的语法格式
    .pipe(uglify())//uglify():压缩
    .pipe(gulp.dest(paths.js.dest))
    .pipe(connect.reload());
}



/*
    那么html css 和 js 都完成了,那么现在还剩img和第三方的插件libs文件夹中的东西,这些都不需要我们再进行压缩等二此操作,所以这两个直接从src问价夹中转到dist文件夹中即可
*/

//4.指定img任务:从src目录里拿到所有图片,移动到dist即可
const img = () =>{
    return gulp.src(paths.img.src)//所有图片文件都是在images文件夹中放着
    .pipe(gulp.dest(paths.img.dest));
}


//5.指定libs任务:从src目录里拿到所有libs文件,移动到dist即可
const libs = () =>{
    return gulp.src(paths.libs.src)
    .pipe(gulp.dest(paths.libs.dest));
}


/*
    服务器的根目录是dist因为,其他目录src是用来放源代码,外层目录是用用来做准备工作,而在dist中才是放最后完成准备的代码的,所以根目录使用他,最后运行在项目中也是dist文件夹中的程序

    从此以后,运行程序就不要用html来直接运行了,要用localhost:端口号来运行程序

    所以就需要运行一个服务器,监听一个端口,当有访问的时候运行程序
*/

//6.开启服务器任务:端口号8080,根目录是dist,支持热更新
    /**
     * 那么若是出现前后端的端口号不一致的话,前端就访问不了后端数据的情况时,如何解决?
     * 使用基于Node.js的一个插件可使前端通过这个介质访问到后端数据
     * 原理是:因为在前端中浏览器的同源策略使得浏览器不能够访问其他端口号的东西,而在两台服务器中却可以轻松实现相互访问,Node.js其实是基于js的一个运行环境(也可说是一个服务器之类),所以呢我们就可以让前端通过访问Node而Node又将其给代理到某个后端接口上,这样就可以实现端口号不一致来访问服务器
     * 方法:通过检测比如说是点击按钮,然后访问后端的80端口下的api文件夹中的index.php中的文件,然后通过判断点击按钮返回的这个链接路径中是否存在api然后判断是否启动这个中间层代理,然后访问服务器数据
     */
const server = () =>{
    connect.server({
        port: 8080,//监听8080端口,现在你就能通过访问localhost:8080端口来访问html页面
        root: 'dist',//需要运行文件所在的根目录
        livereload: true,//热跟新,即不用我更改完页面后,又得手动刷新页面了,每当我更改完页面保存后,他就能自动更新,注意要想实现热更新,还得配合html css 和 js 改变后重新加载的语句:pipe(connect.reload()),一定要加在 html js css语句后,否则实现不了
        middleware(){
            return[
                proxy('/api',{
                    target:'http://localhost:80'
                }),//意思是通过Node插件方法判断路径是是否存在/api,若存在则通过中间层代理到80端口的服务器中,就是说只要你前端是 /api开头的(绝对路径)开头的我就给你代理到80端口上去
                proxy('/uesr',{
                    target:'http://localhost:8008'
                })//除此之外我们还可以配置多个代理中间层,这个是以/uesr开头的就给配置到8008端口上去,此处若是对/user和/api不理解的详见上边解析
            ]
        }
    })
}



//7.指定监听任务:监听文件修改,自动重启对应任务,只要是修改后保存了就会自动重启相应的任务
const watch = () =>{
    gulp.watch(paths.html.src, html)
    gulp.watch(paths.css.src, css)
    gulp.watch(paths.js.src, js)
    /*
        只用监听html css 和 js 的更改即可,没必要再监听images libs的改变了,因为这些都很少会去更改,如果一直开着会造成资源的浪费,如果改了则手动重启一下服务即可
        但是要注意:只有html css 和 js 更改了才会自动重启,若是更改的是本页面的话那么你还得手动重启一下本页面
    */
}






/*
    优化程序(2):这样导出,还得一条一条的手动运行才能实现最终结果,怎么才能让他们只用一个任务就运行所有程序

//最后将我们指定的任务导出,然后在命令中执行就可以了
module.exports = {
    delDist,//删除掉dist文件夹之后,再一一运行以下程序再重新更新dist文件夹内容
    html,
    css,
    js,
    img,
    libs
}//在命令中运行后就可以去dist文件夹中寻找了,亲试成功
*/
// 我们只需要导出一个默认任务,这个默认任务里就包含了我们想要执行的所有任务
// series是同步,意味着第一个任务执行结束了才能执行第二个
    /*
        同步即是程序中的异步会一条一条的按顺序执行语句,所以让删除文件任务和其他文价任务用这样的方式执行,就能实现先删除dist文件夹再重新创建压缩其他文件
    */
// parallel是异步,意味着这些任务是同时开始运行的
    /*
        在执行完删除dist文件夹任务后,开始执行其他任务,而其他任务不分先后关系的,所以其他任务用异步方法一块执行即可
    */
module.exports.default = gulp.series(delDist, gulp.parallel(server,html,js,css,img,libs,watch));//这样就能在命令窗口中只用输入 gulp defaults 就能运行所有的操作了,或者是直接 gulp 运行